package com.chiaching.chaoxingsecondkill.hander;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import com.chiaching.chaoxingsecondkill.domain.SubmitSeatSuccessInfo;
import com.chiaching.chaoxingsecondkill.domain.SubmitSeatUrlInfo;
import com.chiaching.chaoxingsecondkill.domain.UserInfo;
import com.chiaching.chaoxingsecondkill.mapper.SubmitSeatSuccessInfoMapper;
import com.chiaching.chaoxingsecondkill.utils.DingUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Component;

import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author jiajing.he
 * @date 3/23/21 3:34 PM
 */
@Slf4j
@Component
public class SubmitSeatFuture implements Runnable {

    private UserInfo userInfo;

    private boolean isAdmin;

    public static AtomicInteger OFFSET_TIME = new AtomicInteger(0);

    public final static Pattern compile = Pattern.compile("token:\\s'\\S+");

    public final static String USER_AGENT_VALUE = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Mobile Safari/537.36";

    public final static String USER_AGENT_KEY = "User-Agent";

    public final static String COOKIE = "Cookie";

    /**
     * 这个关键id应该就是代表 沙子坳校区
     */
    public final static String DEPT_IDENC="cc061368ad68d8d1";

    public List<String> timeInterval = new ArrayList<>();

    private SubmitSeatSuccessInfoMapper iSubmitSeatSuccessInfoService;

    /**
     * 可选砂子坳校区自习室列表
     */
    public final static String CLASSROOM_LIST_URL="http://office.chaoxing.com/front/third/apps/seat/list?deptIdEnc=cc061368ad68d8d1";


    public SubmitSeatFuture() {
    }

    public SubmitSeatFuture(UserInfo userInfo, List<String> timeInterval, boolean isAdmin,SubmitSeatSuccessInfoMapper iSubmitSeatSuccessInfoService) {
        this.userInfo = userInfo;
        this.isAdmin = isAdmin;
        this.timeInterval = timeInterval;
        this.iSubmitSeatSuccessInfoService=iSubmitSeatSuccessInfoService;
    }

    @Override
    public void run() {
        for (SubmitSeatUrlInfo submitSeatApiUrl : getSubmitSeatApiUrls(userInfo, timeInterval)) {
            if (userInfo.isSkip(submitSeatApiUrl.getTime()) && !isAdmin) {
                //log.info("用户:{} skip{}", userInfo.getName(), submitSeatApiUrl.getTime());
                continue;
            }
            submitSeatApiUrl.setOffSet(OFFSET_TIME.get());
            HashMap<String, String> headers = new HashMap<>(8);
            headers.put(COOKIE, userInfo.getCookies());
            headers.put(USER_AGENT_KEY, USER_AGENT_VALUE);
            try {
                String res = HttpUtil.createGet(submitSeatApiUrl.getUrl()).addHeaders(headers).execute().body();
                JSONObject jsonObject = new JSONObject(res);
                log.info("用户[{}] 座位[{}] 时间偏移量[{}] 时间段[{}] 处理结果[{}]", userInfo.getName(), userInfo.getSeatNum()
                        , SubmitSeatFuture.OFFSET_TIME.get(), submitSeatApiUrl.getTime(),res);
                if (jsonObject.getBool("success")) {
                    String msg = String.format("用户:%s,抢座成功!座位号:%s,时间段:%s", userInfo.getName(), userInfo.getSeatNum(), submitSeatApiUrl.getTime());
                    log.info(msg);
                    DingUtil.sendMsg(msg);
                    userInfo.addTime(submitSeatApiUrl.getTime());
                    saveinfo(userInfo, submitSeatApiUrl, Boolean.TRUE,res);
                } else {
                    //非法预约有种可能是多线程刷新token导致靠前一批挂起的线程token失效
                    String msg = jsonObject.getStr("msg");
                    if (StringUtils.isNotBlank(msg) && (msg.contains("有预约") || msg.contains("该时间段已过")) && OFFSET_TIME.get() == 0) {
                        userInfo.addTime(submitSeatApiUrl.getTime());
                    }
                    if (StringUtils.isNotBlank(msg) && msg.contains("未登录")){
                        DingUtil.sendMsg(userInfo.getName() + "登录信息已经失效!  账号:"+userInfo.getPhone()+" 密码:"+userInfo.getPassword());
                    }
                    saveinfo(userInfo, submitSeatApiUrl, Boolean.FALSE,res);
                }
            } catch (Exception e) {
                log.error("用户[{}] time[{}] seatNum[{}] offSetTime[{}]执行抢座失败！", userInfo.getName(), submitSeatApiUrl.getTime(),
                        userInfo.getSeatNum(), OFFSET_TIME.get(), e);
            }
        }
    }

    private void saveinfo(UserInfo userInfo,SubmitSeatUrlInfo submitSeatApiUrl,boolean success,String msg){
        /*SecondKillHandler.threadPoolExecutor.execute(() ->{
            try {
                SubmitSeatSuccessInfo submitSeatSuccessInfo = new SubmitSeatSuccessInfo();
                submitSeatSuccessInfo.setUserName(userInfo.getName());
                submitSeatSuccessInfo.setSuccess(success?1:0);
                submitSeatSuccessInfo.setPhone(userInfo.getPhone());
                submitSeatSuccessInfo.setSeatNum(Integer.valueOf(submitSeatApiUrl.getSeatNum().trim()));
                Integer offSet = submitSeatApiUrl.getOffSet();
                offSet=Objects.isNull(offSet)?0:offSet;
                Calendar instance = Calendar.getInstance();
                instance.add(Calendar.DAY_OF_MONTH, offSet);
                submitSeatSuccessInfo.setTime(DateUtil.formatDate(instance.getTime())+"-"+submitSeatApiUrl.getTime());
                submitSeatSuccessInfo.setCreateTime(new Date());
                submitSeatSuccessInfo.setUpdateTime(new Date());
                submitSeatSuccessInfo.setMsg(msg);
                iSubmitSeatSuccessInfoService.insert(submitSeatSuccessInfo);
            } catch (Exception e) {
                log.warn("保存日志失败!", e);
            }
        });*/
    }

    /**
     * @return 获取四个时间段的抢座地址
     */
    public static List<SubmitSeatUrlInfo> getSubmitSeatApiUrls(UserInfo userInfo, List<String> timeInterval) {
        ArrayList<SubmitSeatUrlInfo> urls = new ArrayList();
        String submitSeatToken = getSubmitSeatToken(userInfo);
        if (StrUtil.isBlank(submitSeatToken)){
            DingUtil.sendMsg(userInfo.getName() + "登录信息已经失效!  账号:"+userInfo.getPhone()+" 密码:"+userInfo.getPassword());
            log.warn("用户:{} 登录信息已经失效 请重新设置! 账号:{} 密码:{}",userInfo.getName(),userInfo.getPhone(),userInfo.getPassword());
        }
        for (String time : timeInterval) {
            String[] split = time.split("-");
            SubmitSeatUrlInfo submitSeatUrlInfo = new SubmitSeatUrlInfo();
            submitSeatUrlInfo.setTime(time);
            submitSeatUrlInfo.setSeatNum(userInfo.getSeatNum());
            Calendar instance = Calendar.getInstance();
            instance.add(Calendar.DAY_OF_MONTH, OFFSET_TIME.get());
            submitSeatUrlInfo.setUrl(String.format("http://office.chaoxing.com/data/apps/seat/submit?roomId=5559&startTime=%s&endTime=%s&day=%s&seatNum=%s&token=%s", URLEncoder.encode(split[0]), URLEncoder.encode(split[1]), DateUtil.format(instance.getTime(), "yyyy-MM-dd"), userInfo.getSeatNum(), submitSeatToken));
            urls.add(submitSeatUrlInfo);
        }
        return urls;
    }

    public static String getSubmitSeatToken(UserInfo userInfo) {
        HttpRequest post = HttpUtil.createPost(getSelectSeatHtmlUrl(userInfo));
        HashMap<String, String> headers = new HashMap<>(8);
        headers.put(COOKIE, userInfo.getCookies());
        headers.put(USER_AGENT_KEY, USER_AGENT_VALUE);
        post.addHeaders(headers);
        HttpResponse execute = post.execute();
        String body = execute.body();
        Document parse = Jsoup.parse(body);
        Elements script = parse.getElementsByTag("script");
        for (Element element : script) {
            if (element.toString().contains("token")) {
                String res = element.toString();
                Matcher matcher = compile.matcher(res);
                if (matcher.find()) {
                    return matcher.group().substring(8).replace("'", "");
                }
            }
        }
        return "";
    }


    public static String getSelectSeatHtmlUrl(UserInfo userInfo) {
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DAY_OF_MONTH, OFFSET_TIME.get());
        return String.format("http://office.chaoxing.com/front/third/apps/seat/select?id=5559&day=%s&backLevel=2&pageToken=%s&fidEnc=%s", DateUtil.format(instance.getTime(), "yyyy-MM-dd"),getPageToken(userInfo),DEPT_IDENC);
    }

    public static String getPageToken(UserInfo userInfo){
        HttpRequest post = HttpUtil.createGet(CLASSROOM_LIST_URL);
        HttpResponse execute = post
                .header(USER_AGENT_KEY, USER_AGENT_VALUE)
                .header(Header.COOKIE, userInfo.getCookies())
                .execute();
        String body = execute.body();Document parse = Jsoup.parse(body);
        return body.substring(body.indexOf("&pageToken=") + 11, body.indexOf("&fidEnc=")).replace("=", "")
                .replace("'", "")
                .replace(" ", "")
                .replace("+", "");
    }


}
